﻿using Nop.Admin.Extensions;
using Nop.Admin.Models.Customers;
using Nop.Core.Domain.Customers;
using Nop.Plugin.Misc.ECustomerList.Models;
using Nop.Plugin.Misc.ECustomerList.Services;
using Nop.Services.Authentication.External;
using Nop.Services.Common;
using Nop.Services.Customers;
using Nop.Services.Helpers;
using Nop.Services.Localization;
using Nop.Services.Security;
using Nop.Web.Framework.Controllers;
using Nop.Web.Framework.Kendoui;
using Nop.Web.Framework.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;

namespace Nop.Plugin.Misc.ECustomerList.Controllers
{
    [AdminAuthorize]
    public class MiscECustomerListController : BasePluginController
    {

        #region Fields

        private readonly ICustomerService _customerService;
        private readonly IDateTimeHelper _dateTimeHelper;
        private readonly ILocalizationService _localizationService;
        private readonly CustomerSettings _customerSettings;
        private readonly IPermissionService _permissionService;
        private readonly IOpenAuthenticationService _openAuthenticationService;

        private readonly IECustomerListService _extendedCustomerListService;
        #endregion

        #region Constructors

        public MiscECustomerListController(ICustomerService customerService,
            IDateTimeHelper dateTimeHelper,
            ILocalizationService localizationService, 
            CustomerSettings customerSettings,
            IPermissionService permissionService, 
            IOpenAuthenticationService openAuthenticationService,
            IECustomerListService extendedCustomerListService)
        {
            this._customerService = customerService;
            this._dateTimeHelper = dateTimeHelper;
            this._localizationService = localizationService;
            this._customerSettings = customerSettings;
            this._permissionService = permissionService;
            this._openAuthenticationService = openAuthenticationService;
            this._extendedCustomerListService = extendedCustomerListService;
        }

        #endregion

        #region Utilities

        [NonAction]
        protected string GetCustomerRolesNames(IList<CustomerRole> customerRoles, string separator = ",")
        {
            var sb = new StringBuilder();
            for (int i = 0; i < customerRoles.Count; i++)
            {
                sb.Append(customerRoles[i].Name);
                if (i != customerRoles.Count - 1)
                {
                    sb.Append(separator);
                    sb.Append(" ");
                }
            }
            return sb.ToString();
        }


        [NonAction]
        protected IList<CustomerModel.AssociatedExternalAuthModel> GetAssociatedExternalAuthRecords(Customer customer)
        {
            if (customer == null)
                throw new ArgumentNullException("customer");

            var result = new List<CustomerModel.AssociatedExternalAuthModel>();
            foreach (var record in _openAuthenticationService.GetExternalIdentifiersFor(customer))
            {
                var method = _openAuthenticationService.LoadExternalAuthenticationMethodBySystemName(record.ProviderSystemName);
                if (method == null)
                    continue;

                result.Add(new CustomerModel.AssociatedExternalAuthModel()
                {
                    Id = record.Id,
                    Email = record.Email,
                    ExternalIdentifier = record.ExternalIdentifier,
                    AuthMethodName = method.PluginDescriptor.FriendlyName
                });
            }

            return result;
        }

        [NonAction]
        protected CustomerModel PrepareCustomerModelForList(Customer customer)
        {
            return new CustomerModel()
            {
                Id = customer.Id,
                Email = customer.IsRegistered() ? customer.Email : _localizationService.GetResource("Admin.Customers.Guest"),
                Username = customer.Username,
                FullName = customer.GetFullName(),
                Company = customer.GetAttribute<string>(SystemCustomerAttributeNames.Company),
                Phone = customer.GetAttribute<string>(SystemCustomerAttributeNames.Phone),
                ZipPostalCode = customer.GetAttribute<string>(SystemCustomerAttributeNames.ZipPostalCode),
                CustomerRoleNames = GetCustomerRolesNames(customer.CustomerRoles.ToList()),
                Active = customer.Active,
                CreatedOn = _dateTimeHelper.ConvertToUserTime(customer.CreatedOnUtc, DateTimeKind.Utc),
                LastActivityDate = _dateTimeHelper.ConvertToUserTime(customer.LastActivityDateUtc, DateTimeKind.Utc),
                //external authentication records
                AssociatedExternalAuthRecords = GetAssociatedExternalAuthRecords(customer),
            };
        }

        #endregion

        public ActionResult Index()
        {
            return RedirectToAction("List");
        }

        public ActionResult List()
        {
            //load registered customers by default
            var defaultRoleIds = new[] { _customerService.GetCustomerRoleBySystemName(SystemCustomerRoleNames.Registered).Id };
            var listModel = new ECustomerListModel()
            {
                UsernamesEnabled = _customerSettings.UsernamesEnabled,
                DateOfBirthEnabled = _customerSettings.DateOfBirthEnabled,
                CompanyEnabled = _customerSettings.CompanyEnabled,
                PhoneEnabled = _customerSettings.PhoneEnabled,
                ZipPostalCodeEnabled = _customerSettings.ZipPostalCodeEnabled,
                AvailableCustomerRoles = _customerService.GetAllCustomerRoles(true).Select(cr => cr.ToModel()).ToList(),
                SearchCustomerRoleIds = defaultRoleIds,
            };
            //more search options
            listModel.AvailableMoreCustomerSearchOptions.Insert(0, new SelectListItem() { Text = _localizationService.GetResource("Admin.Common.All"), Value = "0" });
            listModel.AvailableMoreCustomerSearchOptions.Insert(1, new SelectListItem() { Text = _localizationService.GetResource("Plugins.Misc.ECustomerList.Active"), Value = "1" });
            listModel.AvailableMoreCustomerSearchOptions.Insert(2, new SelectListItem() { Text = _localizationService.GetResource("Plugins.Misc.ECustomerList.NotActive"), Value = "2" });
            listModel.AvailableMoreCustomerSearchOptions.Insert(3, new SelectListItem() { Text = _localizationService.GetResource("Plugins.Misc.ECustomerList.ShowDeleted"), Value = "3" });

            //external customer search
            listModel.AvailableExternalSearchOptions.Insert(0, new SelectListItem() { Text = _localizationService.GetResource("Admin.Common.All"), Value = "0" });
            listModel.AvailableExternalSearchOptions.Insert(1, new SelectListItem() { Text = _localizationService.GetResource("Plugins.Misc.ECustomerList.InternalCustomersOnly"), Value = "1" });
            listModel.AvailableExternalSearchOptions.Insert(2, new SelectListItem() { Text = _localizationService.GetResource("Plugins.Misc.ECustomerList.ExternalCustomersOnly"), Value = "2" });

            return View("~/Plugins/Misc.ECustomerList/Views/List.cshtml", listModel);           
        }


        [HttpPost]
        public ActionResult CustomerList(DataSourceRequest command, ECustomerListModel model,
            [ModelBinder(typeof(CommaSeparatedModelBinder))] int[] searchCustomerRoleIds)
        {
            //we use own own binder for searchCustomerRoleIds property 
 
            var searchDayOfBirth = 0;
            int searchMonthOfBirth = 0;
            if (!String.IsNullOrWhiteSpace(model.SearchDayOfBirth))
                searchDayOfBirth = Convert.ToInt32(model.SearchDayOfBirth);
            if (!String.IsNullOrWhiteSpace(model.SearchMonthOfBirth))
                searchMonthOfBirth = Convert.ToInt32(model.SearchMonthOfBirth);

            var customers = _extendedCustomerListService.GetAllCustomers(
                customerRoleIds: searchCustomerRoleIds,
                email: model.SearchEmail,
                username: model.SearchUsername,
                firstName: model.SearchFirstName,
                lastName: model.SearchLastName,
                dayOfBirth: searchDayOfBirth,
                monthOfBirth: searchMonthOfBirth,
                company: model.SearchCompany,
                phone: model.SearchPhone,
                zipPostalCode: model.SearchZipPostalCode,
                loadOnlyWithShoppingCart: false,
                pageIndex: command.Page - 1,
                pageSize: command.PageSize,
                customerSearchOptions: model.CustomerMoreSearchOptionsId,
                externalSearchOptions: model.ExternalSearchOptionsId
                );
            var gridModel = new DataSourceResult
            {
                Data = customers.Select(PrepareCustomerModelForList),
                Total = customers.TotalCount
            };

            return Json(gridModel);
        }
    }
}
